﻿// Developer Express Code Central Example:
// How to draw a rectangle around selected cells and implement a copy/past functionality
// 
// Unlike the Excel sheet, the XtraGrid doesn't provide a copy/paste functionality,
// because it displays data of different types and therefore. So, this
// functionality can't be used in common situations. This example demonstrates how
// to implement a copy/paste functionality manually, assuming that all data is of
// the String type. Also, this example demonstrates how to draw a blinking
// rectangle around the selected area using the GridView.CustomDrawCell event. The
// CellSelectionHelper component, created within this example, can be simply placed
// on the form in the VS designer. All you need to make it work is to assign an
// appropriate GridView to it.
// 
// You can find sample updates and versions for different programming languages here:
// http://www.devexpress.com/example=E1603

using DevExpress.XtraGrid.Views.BandedGrid;
using System;
using DevExpress.Data;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Drawing;
using DevExpress.XtraGrid.Views.Base;
using System.Drawing.Drawing2D;
using System.ComponentModel;

namespace MSoft.Shipping.Control
{
    public class BandedCellSelectionHelper : Component
    {
        private bool disposed = false;
        private string[,] selection;
        private Rectangle selectedArea = Rectangle.Empty;
        private Bitmap evenPicture;
        private Bitmap oddPicture;        
        private Timer timer;


        private const int selectionBorderWidth = 2;
        private Color color = Color.Red;

        public BandedCellSelectionHelper(BandedGridView view)
        {
            if (!DesignMode)
            {
                timer = new Timer();
                timer.Tick += new EventHandler(OnTimerTick);
                timer.Start();
            }
            View = view;
            selectedArea.X = int.MaxValue;
        }

        public BandedCellSelectionHelper(DevExpress.XtraGrid.GridControl gridControl_Material)
        {
            // TODO: Complete member initialization
            this.gridControl_Material = gridControl_Material;
        }

        private BandedGridView fView;
        private DevExpress.XtraGrid.GridControl gridControl_Material;
        public BandedGridView View
        {
            get { return fView; }
            set
            {
                if (fView == value) return;
                if (fView != null)
                    UnsubscribeViewEvents();
                fView = value;
                if (value != null)
                    SubscribeViewEvents();
            }
        }

        public Bitmap EvenPicture
        {
            get
            {
                if (evenPicture == null)
                    evenPicture = CreateBitmap(true);
                return evenPicture;
            }
            set
            {
                if (evenPicture != null && evenPicture.Tag.ToString() == "DXSample")
                    evenPicture.Dispose();
                evenPicture = value;
            }
        }

        public Bitmap OddPicture
        {
            get
            {
                if (oddPicture == null)
                    oddPicture = CreateBitmap(false);
                return oddPicture;
            }
            set
            {
                if (oddPicture != null && oddPicture.Tag.ToString() == "DXSample")
                    oddPicture.Dispose();
                oddPicture = value;
            }
        }

        private void OnSelectionChanged(object sender, DevExpress.Data.SelectionChangedEventArgs e)
        {
            var view = sender as BandedGridView;
            ClearSelection();
            GridCell[] cells = view.GetSelectedCells();
            if (cells.Length == 0) return;
            int minCol, minRow, maxCol, maxRow;
            minCol = minRow = int.MaxValue;
            maxCol = maxRow = 0;
            foreach (GridCell cell in cells)
            {
                minCol = Math.Min(cell.Column.VisibleIndex, minCol);
                //minRow = Math.Min(cell.RowHandle, minRow);
                maxCol = Math.Max(cell.Column.VisibleIndex, maxCol);
                //maxRow = Math.Max(cell.RowHandle, maxRow);
            }
            minRow = 0;
            maxRow = view.RowCount;
            selectedArea = new Rectangle(minCol, minRow, maxCol - minCol, maxRow - minRow);
        }

        private void OnGridViewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.C:
                    if (e.Control)
                    {
                        ClearSelection();
                        GridCell[] cells = fView.GetSelectedCells();
                        if (cells.Length == 0) return;
                        int minCol, minRow, maxCol, maxRow;
                        minCol = minRow = int.MaxValue;
                        maxCol = maxRow = 0;
                        foreach (GridCell cell in cells)
                        {
                            minCol = Math.Min(cell.Column.VisibleIndex, minCol);
                            //minRow = Math.Min(cell.RowHandle, minRow);
                            maxCol = Math.Max(cell.Column.VisibleIndex, maxCol);
                            //maxRow = Math.Max(cell.RowHandle, maxRow);
                        }
                        minRow = 0;
                        maxRow = fView.RowCount;
                        selection = new string[maxCol - minCol + 1, maxRow - minRow + 1];
                        foreach (GridCell cell in cells)
                            selection[cell.Column.VisibleIndex - minCol, cell.RowHandle - minRow] =
                                fView.GetRowCellValue(cell.RowHandle, cell.Column).ToString();
                        selectedArea = new Rectangle(minCol, minRow, maxCol - minCol, maxRow - minRow);
                    }
                    break;
                case Keys.V:
                    if (e.Control)
                    {
                        Clipboard.Clear();
                        fView.GridControl.BeginInvoke(new MethodInvoker(Paste));
                    }
                    break;
                case Keys.Escape: ClearSelection(); break;
            }
        }

        private void Paste()
        {
            if (selection == null) return;
            for (int i = 0; i <= selectedArea.Width; i++)
                for (int j = 0; j <= selectedArea.Height; j++)
                {
                    if (i + fView.FocusedColumn.VisibleIndex > fView.VisibleColumns.Count - 1 ||
                        j + fView.FocusedRowHandle > fView.RowCount - 1) continue;
                    fView.SetRowCellValue(j + fView.FocusedRowHandle,
                        fView.VisibleColumns[i + fView.FocusedColumn.VisibleIndex], selection[i, j]);
                }
            ClearSelection();
        }

        private Bitmap CreateBitmap(bool even)
        {
            if (fView == null) return null;
            Bitmap result = new Bitmap(fView.GridControl.Bounds.Width, fView.GridControl.Bounds.Height);
            using (Graphics g = Graphics.FromImage(result))
            {
                Color foreColor = even ? Color.AliceBlue : Color.AntiqueWhite;
                Color backColor = even ? Color.AntiqueWhite : Color.AliceBlue;
                using (Brush brush = new HatchBrush(HatchStyle.BackwardDiagonal, foreColor, backColor))
                {
                    g.FillRectangle(brush, new Rectangle(Point.Empty, result.Size));
                }
            }
            result.Tag = "DXSample";
            return result;
        }

        private void DrawArea(Graphics g, Rectangle area)
        {
            area.Inflate(0, 0);
            Brush brush = new SolidBrush(color);
            g.FillRectangle(brush, area);

        }

        private void DrawLine(Graphics g, Point p1, Point p2)
        {
            Pen pen = new Pen(color);
            g.DrawLine(pen, p1, p2);
        }

        private bool IsPointInRange(int point, bool vertical)
        {
            if (vertical) return point >= selectedArea.Top && point <= selectedArea.Bottom;
            else return point >= selectedArea.Left && point <= selectedArea.Right;
        }

        private void OnTimerTick(object sender, EventArgs e)
        {
            //even = !even;
            //if (selectedArea.X == int.MaxValue) return;
            //for (int i = selectedArea.Left; i <= selectedArea.Right; i++)
            //    for (int j = selectedArea.Top; j <= selectedArea.Bottom; j++)
            //        fView.InvalidateRowCell(j, fView.VisibleColumns[i]);
        }

        private void ClearSelection()
        {
            selection = null;
            selectedArea.X = int.MaxValue;
            fView.Invalidate();
        }

        protected override void Dispose(bool disposing)
        {
            if (!disposed && disposing)
            {
                if (fView != null)
                {
                    UnsubscribeViewEvents();
                    fView = null;
                }
                if (evenPicture != null && object.ReferenceEquals(evenPicture.Tag, "DXSample"))
                {
                    evenPicture.Dispose();
                    evenPicture = null;
                }
                if (evenPicture != null && object.ReferenceEquals(oddPicture.Tag, "DXSample"))
                {
                    oddPicture.Dispose();
                    oddPicture = null;
                }
                if (timer != null)
                {
                    timer.Stop();
                    timer.Tick -= new EventHandler(OnTimerTick);
                    timer.Dispose();
                    timer = null;
                }
                disposed = true;
            }
            base.Dispose(disposing);
        }

        void GridControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            try
            {
                #region Paint
                var gridControl = (sender as DevExpress.XtraGrid.GridControl);
                var view = gridControl.FocusedView as BandedGridView;
                DevExpress.XtraGrid.Views.BandedGrid.ViewInfo.BandedGridViewInfo vi = view.GetViewInfo() as DevExpress.XtraGrid.Views.BandedGrid.ViewInfo.BandedGridViewInfo;
                Pen standardPen = new Pen(fView.PaintAppearance.Row.BackColor);
                Pen pen = Pens.Red;
                Point p1 = Point.Empty;
                Point p2 = Point.Empty;
                Rectangle drawingArea = Rectangle.Empty;
                if (selectedArea.X == int.MaxValue) return;
                foreach (DevExpress.XtraGrid.Views.Grid.ViewInfo.GridRowInfo ri in vi.RowsInfo)
                {
                    foreach (DevExpress.XtraGrid.Columns.GridColumn column in view.VisibleColumns)
                    {
                        //Bottom
                        if (ri.RowHandle == selectedArea.Bottom && IsPointInRange(column.VisibleIndex, false))
                        {
                            drawingArea = new Rectangle(vi.ColumnsInfo[column].Bounds.X, ri.Bounds.Bottom - selectionBorderWidth, ri.Bounds.Width, selectionBorderWidth);
                            if (column.VisibleIndex == selectedArea.Right) drawingArea.Width -= selectionBorderWidth;
                        }
                        if (drawingArea != Rectangle.Empty)
                        {
                            DrawArea(e.Graphics, drawingArea);
                            drawingArea = Rectangle.Empty;
                        }
                        //Left
                        if (column.VisibleIndex == selectedArea.Left && IsPointInRange(ri.RowHandle, true))
                        {
                            if (vi.ColumnsInfo[column] != null)
                            {
                                drawingArea = new Rectangle(vi.ColumnsInfo[column].Bounds.X, ri.Bounds.Y, selectionBorderWidth, vi.ColumnsInfo[column].Bounds.Height);
                                if (ri.RowHandle == selectedArea.Bottom) drawingArea.Height -= selectionBorderWidth;
                            }
                        }
                        if (drawingArea != Rectangle.Empty)
                        {
                            DrawArea(e.Graphics, drawingArea);
                            drawingArea = Rectangle.Empty;
                        }
                        //Right
                        if (column.VisibleIndex == selectedArea.Right && IsPointInRange(ri.RowHandle, true))
                        {
                            if (vi.ColumnsInfo[column] != null)
                            {
                                drawingArea = new Rectangle(vi.ColumnsInfo[column].Bounds.Right - selectionBorderWidth, ri.Bounds.Y, selectionBorderWidth,
                                    vi.ColumnsInfo[column].Bounds.Height);
                            }
                        }
                        if (drawingArea != Rectangle.Empty)
                        {
                            DrawArea(e.Graphics, drawingArea);
                            drawingArea = Rectangle.Empty;
                        }
                    }

                    DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewRects rects = vi.ViewRects;
                    Rectangle er = rects.EmptyRows;
                    if (er.IsEmpty == false)
                    {
                        //DevExpress.XtraGrid.Grid.Drawing
                        foreach (DevExpress.XtraGrid.Drawing.GridColumnInfoArgs column in vi.ColumnsInfo)
                        {
                            int x = column.Bounds.Right - selectionBorderWidth;

                            if (column.Column != null)
                            {
                                /*
                                 * Header
                                 * */

                                //Left
                                if (column.Column.VisibleIndex == selectedArea.Left)
                                {
                                    drawingArea = new Rectangle(column.Bounds.X, column.Bounds.Y, selectionBorderWidth, column.Bounds.Height);
                                }
                                if (drawingArea != Rectangle.Empty)
                                {
                                    DrawArea(e.Graphics, drawingArea);
                                    drawingArea = Rectangle.Empty;
                                }
                                //Right
                                if (column.Column.VisibleIndex == selectedArea.Right)
                                {
                                    drawingArea = new Rectangle(column.Bounds.Right - selectionBorderWidth, column.Bounds.Y, selectionBorderWidth, column.Bounds.Height);
                                }
                                if (drawingArea != Rectangle.Empty)
                                {
                                    DrawArea(e.Graphics, drawingArea);
                                    drawingArea = Rectangle.Empty;
                                }

                                //Top
                                if (column.Column.VisibleIndex >= selectedArea.Left && column.Column.VisibleIndex <= selectedArea.Right)
                                {
                                    drawingArea = new Rectangle(column.Bounds.Left, column.Bounds.Y, column.Bounds.Width, selectionBorderWidth);
                                }
                                if (drawingArea != Rectangle.Empty)
                                {
                                    DrawArea(e.Graphics, drawingArea);
                                    drawingArea = Rectangle.Empty;
                                }
                            }

                            if (column.Type != DevExpress.XtraGrid.Views.Grid.ViewInfo.GridColumnInfoType.Indicator)
                            {
                                /*
                                * Empty Row
                                * */
                                //Left
                                if (column.Column.VisibleIndex == selectedArea.Left)
                                {
                                    drawingArea = new Rectangle(column.Bounds.Left, er.Top, selectionBorderWidth, er.Bottom);
                                }

                                if (drawingArea != Rectangle.Empty)
                                {
                                    DrawArea(e.Graphics, drawingArea);
                                    drawingArea = Rectangle.Empty;
                                }
                                //Right
                                if (column.Column.VisibleIndex == selectedArea.Right)
                                {
                                    drawingArea = new Rectangle(column.Bounds.Right - selectionBorderWidth, er.Top, selectionBorderWidth, er.Bottom);
                                }

                                if (drawingArea != Rectangle.Empty)
                                {
                                    DrawArea(e.Graphics, drawingArea);
                                    drawingArea = Rectangle.Empty;
                                }
                                //Bottom
                                if (column.Column.VisibleIndex >= selectedArea.Left && column.Column.VisibleIndex <= selectedArea.Right)
                                {
                                    drawingArea = new Rectangle(column.Bounds.Left, er.Bottom, column.Bounds.Width, selectionBorderWidth);
                                }
                                if (drawingArea != Rectangle.Empty)
                                {
                                    DrawArea(e.Graphics, drawingArea);
                                    drawingArea = Rectangle.Empty;
                                }
                            }
                        }
                    }
                    //if (!rects.FixedRight.IsEmpty)
                    //    e.Graphics.DrawLine(pen, rects.FixedRight.Left - selectionBorderWidth, er.Top, rects.FixedRight.Left - selectionBorderWidth, er.Bottom);
                }
                #endregion
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
        }

        private void SubscribeViewEvents()
        {
            fView.SelectionChanged += new SelectionChangedEventHandler(OnSelectionChanged);
            fView.GridControl.Paint += new PaintEventHandler(GridControl_Paint);
        }

        private void UnsubscribeViewEvents()
        {
            //fView.KeyDown -= new KeyEventHandler(OnGridViewKeyDown);
            fView.SelectionChanged -= new SelectionChangedEventHandler(OnSelectionChanged);
            fView.GridControl.Paint -= new PaintEventHandler(GridControl_Paint);
        }
    }
}